package hk.ust.comp3111.ustnutrition;

import hk.ust.comp3111.ustnutrition.FoodListSearchDialog.AdvancedSearchCriteria;
import hk.ust.comp3111.ustnutrition.FoodListSearchDialog.FoodListSearchDialogListener;
import hk.ust.comp3111.ustnutrition.data.DataAccessor;
import hk.ust.comp3111.ustnutrition.data.DataTable;
import hk.ust.comp3111.ustnutrition.data.DataTableListener;
import hk.ust.comp3111.ustnutrition.data.db.Food;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;

import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.GridView;

public class FoodListFragment extends Fragment implements OnItemClickListener,
		FoodListSearchDialogListener, DataTableListener<Food>
{
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setHasOptionsMenu(true);
		DataAccessor.Instance.getFoods().addChangeListener(this);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		DataAccessor.Instance.getFoods().removeChangeListener(this);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View root = inflater.inflate(R.layout.food_list_frag, container, false);
		mGrid = (GridView) root.findViewById(R.id.grid);
		return root;
	}

	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		inflater.inflate(R.menu.food_list, menu);
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		update();
		mGrid.setOnItemClickListener(this);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.sort_by_name:
			sortOrder = SortOrder.ByName;
			update();
			return true;

		case R.id.sort_by_rest_name:
			sortOrder = SortOrder.ByRestName;
			update();
			return true;

		case R.id.sort_by_protein:
			sortOrder = SortOrder.ByProtein;
			update();
			return true;

		case R.id.sort_by_carbo:
			sortOrder = SortOrder.ByCarbo;
			update();
			return true;

		case R.id.sort_by_fat:
			sortOrder = SortOrder.ByFat;
			update();
			return true;
		case R.id.sort_by_sodium:
			sortOrder = SortOrder.BySodium;
			update();
			return true;

		case R.id.search:
			onSearchClick();
			return true;

		default:
			return super.onOptionsItemSelected(item);
		}
	}

	@Override
	public void onAdvancedSearch(AdvancedSearchCriteria criteria)
	{
		this.criteria = criteria;
		update();
	}

	private void update() {
		mFoods = getFoods();
		mGrid.setAdapter(new MyAdapter());
	}

	private Food[] getFoods() {
		DataTable<Food> foodTable = DataAccessor.Instance.getFoods();
		ArrayList<Food> foods = MiscUtils.iteratorToList(foodTable.take(
				foodTable.new RowFilter() {
					@Override
					public boolean filter(Food food) {
						if(criteria == null)
							return true;
						if(criteria.food != null && criteria.food.trim().length() != 0 &&
								!food.getName().toLowerCase(Locale.US).contains(criteria.food.toLowerCase(Locale.US)))
							return false;

						if(criteria.rest != null && criteria.rest.trim().length() != 0 &&
								(food.getRestaurant() == null || !food.getRestaurant().getName().toLowerCase(Locale.US).contains(criteria.rest.toLowerCase(Locale.US))))
							return false;

						if(criteria.isCarbohydrateRich && food.getCarbohydrate() < 100)
							return false;

						if(criteria.isProteinRich && food.getProtein() < 30)
							return false;

						if(criteria.isFatRich && food.getFat() < 30)
							return false;

						if(criteria.isSodiumRich && food.getSodium() < 1)
							return false;

						return true;
					}
				}, -1));

		Collections.sort(foods, new Comparator<Food>() {
			@Override
			public int compare(Food food1, Food food2) {
				switch (sortOrder) {
				case ByName:
					if(food1.getName() == null && food2.getName() == null)
						return 0;
					if(food1.getName() == null)
						return 1;
					else if(food2.getName() == null)
						return -1;
					return food1.getName().toLowerCase(Locale.US).compareTo(food2.getName().toLowerCase(Locale.US));

				case ByRestName:
					return food1.getRestaurantStr().toLowerCase(Locale.US).compareTo(
							food2.getRestaurantStr().toLowerCase(Locale.US));

				case ByProtein:
					return Double.compare(food2.getProtein(),
							food1.getProtein());

				case ByCarbo:
					return Double.compare(food2.getCarbohydrate(),
							food1.getCarbohydrate());

				case ByFat:
					return Double.compare(food2.getFat(), food1.getFat());

				case BySodium:
					return Double.compare(food2.getSodium(), food1.getSodium());

				default:
					return 0;
				}
			}
		});

		Food[] _foods = new Food[foods.size()];
		foods.toArray(_foods);

		return _foods;
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) {
		IntakeRecordDialog dialog = IntakeRecordDialog.createInstance(
				mFoods[position].getId());
		dialog.show(getFragmentManager(), "intake_dialog");
	}

	private void onSearchClick() {
		FoodListSearchDialog dialog = new FoodListSearchDialog();
		dialog.setTargetFragment(this, 0);
		dialog.show(getFragmentManager(), "search_dialog");
	}

	private class MyAdapter extends BaseAdapter {
		@Override
		public int getCount() {
			return mFoods.length;
		}

		@Override
		public Food getItem(int position) {
			return mFoods[position];
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(final int position, View convertView,
				ViewGroup parent)
		{
			FoodListCardView v = (FoodListCardView) convertView;
			if (v == null) {
				v = (FoodListCardView) LayoutInflater.from(getActivity())
						.inflate(R.layout.food_list_card, parent, false);
			}

			Food f = getItem(position);
			v.setFood(f);
			return v;
		}
	}

	private GridView mGrid;
	private Food[] mFoods;
	AdvancedSearchCriteria criteria;
	SortOrder sortOrder = SortOrder.ByName;

	enum SortOrder {
		ByName, ByRestName, ByProtein, ByCarbo, ByFat, BySodium
	}

	Handler handler = new Handler();
	boolean dirty;

	@Override
	public void changed(DataTableListener.ChangeEvent<Food> event) {
		dirty = true;
		handler.postDelayed(new Runnable() {
			@Override
			public void run() {
				if(dirty) {
					dirty = false;
					if (mGrid != null) {
						update();
					}
				}
			}
		}, 500);
	}
}
